package com.gitee.slowcreator.http.util;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.gitee.slowcreator.http.constant.JsonConstant;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * @author zxw
 * @date 2022/11/25
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public abstract class JacksonUtil {

    private static final ObjectMapper objectMapper;

    static {
        objectMapper = new ObjectMapper();
        // 反序列化时，json中包含pojo不存在的字段时，不报错
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.registerModule(new JavaTimeModule());
    }

    public static String toJsonString(Object object) {
        try {
            return objectMapper.writeValueAsString(object);
        } catch (Exception e) {
            log.error("转json字符串出现异常：", e);
            throw new RuntimeException("序列化异常");
        }
    }

    public static byte[] toJsonByte(Object object) {

        try {
            return objectMapper.writeValueAsBytes(object);
        } catch (Exception e) {
            log.error("转json字符串出现异常：", e);
            throw new RuntimeException(e);
        }
    }

    public static <T> T parseObject(String text, Class<T> clazz) {

        parseIfBlank(text);
        try {

            return objectMapper.readValue(text, clazz);
        } catch (Exception e) {
            log.error("解析json字符串出现异常：", e);
            throw new RuntimeException("反序列化异常");
        }
    }

    public static <T> T parseObject(byte[] data, Class<T> clazz) {

        if (ArrayUtil.isEmpty(data)) {
            throw new IllegalArgumentException("解析数据不能为空!");
        }

        try {

            return objectMapper.readValue(data, clazz);
        } catch (Exception e) {
            log.error("解析json字符串出现异常：", e);
            throw new RuntimeException("反序列化异常");
        }
    }

    public static <T> T parseObject(byte[] data, TypeReference<T> typeReference) {

        if (ArrayUtil.isEmpty(data)) {
            throw new IllegalArgumentException("解析数据不能为空!");
        }

        try {

            return objectMapper.readValue(data, typeReference);
        } catch (Exception e) {
            log.error("解析json字符串出现异常：", e);
            throw new RuntimeException("反序列化异常");
        }
    }

    public static <T> T parseObject(String text, TypeReference<T> typeReference) {

        parseIfBlank(text);
        try {
            return objectMapper.readValue(text, typeReference);
        } catch (Exception e) {
            log.error("解析json字符串出现异常：", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 解析json 支持 array 和 object 的解析
     *
     * @param text 解析的 json 数据
     * @return 反序列化后的数据
     */
    public static Object parseObjectOrArray(String text) {

        parseIfBlank(text);
        if (StrUtil.startWith(text, JsonConstant.ARRAY_BEGIN)) {
            // 说明是数组
            return JacksonUtil.parseArray(text, Object.class);
        } else if (StrUtil.startWith(text, JsonConstant.OBJECT_BEGIN)) {
            // 说明是对象
            return JacksonUtil.parseObject(text, new TypeReference<Object>() {
            });
        } else {
            // 未知类型 原数据不替换
            return text;
        }
    }

    public static <T> List<T> parseArray(String text, Class<T> clazz) {

        parseIfBlank(text);
        try {
            return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
        } catch (Exception e) {
            log.error("解析json字符串出现异常：", e);
            throw new RuntimeException(e);
        }
    }

    private static void parseIfBlank(String text) {
        if (StrUtil.isBlank(text)) {

            throw new NullPointerException("parse data is not");
        }
    }
}
